#ifndef ABSTRACT_TASK_H
#define ABSTRACT_TASK_H

#include <string>
#include <functional>
#include <atomic>
#include <mutex>
#include "task_define.h"
#include "context.h"
#include "utils/utils/date_time.h"

namespace task
{

enum TaskEventType: unsigned char
{
    PAUSE = 0,
    RESUME,
    CANCEL
};

using TaskEventNotify = std::function<void(TaskEventType event_type)>;
using TaskChainEventNotify = std::function<void(const std::string &task_chain_name, TaskEventType event_type)>;

enum TaskType: unsigned char
{
    SYNC_TASK = 0,      //长任务
    SYNC_REQUEST_TASK   //短请求任务
};

class AbstractTask;
using AbstractTaskConstPtr = std::shared_ptr<AbstractTask>;
/**
 * @brief:  所有任务的虚基类
 * @author: sherlock_lht
 */
class AbstractTask
{
public:
    explicit AbstractTask(const std::string &name);
    virtual ~AbstractTask() = default;

    /**
     * @brief:  获取全局唯一的任务名称
     * @author: sherlock_lht
     */
    [[nodiscard]] virtual std::string getName() const final;

    /**
     * @brief:  任务主动触发暂停/恢复/取消，以控制整个scheduler的暂停/恢复/取消
     *          接口调用后，会触发相应的onPause/onResume/onCancel
     * @author: sherlock_lht
     */
    void pause();
    void resume();
    void cancel();

    /**
     * @brief:  当前任务所属的任务链的是否处于空闲(任务链未运行)/运行中/暂停状态
     * @author: sherlock_lht
     */
    bool isIdle() const;
    bool isRunning() const;
    bool isPause() const;

    /**
     * @brief:  任务开始时触发，且只触发一次
     * @author: sherlock_lht
     */
    virtual bool onStart() = 0;

    /**
     * @brief:  任务进行中触发，如果返回Running，则继续触发，直到返回Success/Failure为止
     * @author: sherlock_lht
     */
    virtual TaskStatus onRunning() = 0;

    /**
     * @brief:  任务暂停时触发，如果返回false，则暂停无效，任务继续运行
     * @author: sherlock_lht
     */
    virtual bool onPause() = 0;

    /**
     * @brief:  任务恢复时触发，如果返回false，则恢复无效，任务继续暂停
     * @author: sherlock_lht
     */
    virtual bool onResume() = 0;

    /**
     * @brief:  任务取消时触发
     * @author: sherlock_lht
     */
    virtual void onCancel() = 0;

    /**
     * @brief:  当前task执行结束后触发（非异常结束）
     * @param:  res  task结束状态，true：success，false：failure
     * @author: sherlock_lht
     */
    virtual void onDone(bool res);

    /**
     * @brief:  任务运行超时时触发，设定超时时间后，如果超出时间阈值，仍然没有结束(即使在running)，则算超时
     * @return: 返回true，则表示任务继续，返回false，则任务失败
     * @author: sherlock_lht
     */
    virtual bool onTimeout();

    /**
     * @brief:  任务异常退出时触发
     * @author: sherlock_lht
     */
    virtual void onHalt();

    /**
     * @brief:  任务运行响应时触发，仅限reactive策略
     * @return: 返回true：正常响应，任务继续进行，返回false，异常响应，任务异常停止，等同于触发halt
     * @author: sherlock_lht
     */
    virtual bool onReactive();

    virtual TaskType getTaskType() const = 0;

    /**
     * @brief:      开启超时监控，如果超时监控已存在，则重置超时时间
     * @note:       task运行完成后，会自动调用stopTimeout()停止超时判断
     * @timeout:    超时时间，单位：ms
     * @author:     sherlock_lht
     */
    void startTimeout(int64_t timeoutMillSecond);

    /**
     * @brief:  停止超时监控，如果超时未开启，则不会发生任何作用
     * @author: sherlock_lht
     */
    void stopTimeout();

    /**
     * @brief:  当前task是否已经超时
     * @author: sherlock_lht
     */
    [[nodiscard]] bool isTimeout() const;

    /**
     * @brief:  设置上下文数据管理器
     * @author: sherlock_lht
     */
    void setContext(Context *ctx);
    Context *getContext();

    /**
     * @brief:  任务中触发事件
     * @author: sherlock_lht
     */
    void setEventNotify(TaskEventNotify event_notify);
    void eventNotify(TaskEventType task_event_type);

protected:
    /**
     * @brief:  添加上下文数据
     * @author: sherlock_lht
     */
    template<class T>
    bool setContextData(const std::string &key, const T &data)
    {
        if (nullptr != task_context_)
        {
            task_context_->setData(key, data);
            return true;
        }
        return false;
    }

    /**
     * @brief:  获取上下文数据
     * @author: sherlock_lht
     */
    template<class T>
    bool getContextData(const std::string &key, T &data) const
    {
        if (nullptr == task_context_)
        {
            return false;
        }
        return task_context_->getData(key, data);
    }

protected:
    std::string task_name_;
    Context *task_context_;
    int64_t timeout_target_;//超时时间，超出此时间则认为是超时
    std::atomic<bool> timeout_flag_;
    TaskEventNotify event_notify_;
    std::mutex event_notify_mutex_;
};

}


#endif //ABSTRACT_TASK_H
